/******************************************************************************
 cnome: A C++ source "genes" discover. :-)

 See more details at:

   http://www.codeplex.com/cnome

 The original author site is at: http://www.alexandre-barbosa.com/

 Copyright (c) 2008 Alexandre Barbosa.

 Distributed under the MIT License. (See accompanying file LICENSE-MIT.txt 
 or at http://www.codeplex.com/cnome/license)
 ******************************************************************************/

#ifndef DIRECTIVE_BASE_H
#define DIRECTIVE_BASE_H

#include <boost/spirit/home/classic/core/scanner/scanner.hpp>
#include <boost/spirit/home/classic/core/scanner/skipper.hpp>

#include "scopes.h"

namespace cnome { namespace directive {

    template <typename BaseT>
    struct skipper_iteration_policy;

    template <typename BaseT>
    struct drt_skipper_iteration_policy;

    template <typename BaseT>
    struct drt_iteration_policy;

    namespace impl
    {
	using boost::spirit::classic::scanner_policies;
	    
        template <typename RT, typename T, typename ScannerT, typename BaseT>
        inline RT
        drt_parser_parse(
            T const& t,
            ScannerT const& scan,
            skipper_iteration_policy<BaseT> const&)
        {
            typedef scanner_policies<
                drt_iteration_policy<
                    BOOST_DEDUCED_TYPENAME ScannerT::iteration_policy_t>,
                BOOST_DEDUCED_TYPENAME ScannerT::match_policy_t,
                BOOST_DEDUCED_TYPENAME ScannerT::action_policy_t
            > policies_t;

#if defined(CNOME_DEBUG)
            debug_info(before_action,"drt_parser_parse",t.subject(), scan);
#endif

            t.deriv_action_before_parse(scan);

#if defined(CNOME_DEBUG)
            debug_info(before_parse,"drt_parser_parse",t.subject(), scan);
#endif

            scan.skip(scan);
            RT hit = t.subject().parse(scan.change_policies(policies_t(scan)));

#if defined(CNOME_DEBUG)
            debug_info(after_parse,"drt_parser_parse",t, scan);
#endif

            t.deriv_action_after_parse(scan);

#if defined(CNOME_DEBUG)
            debug_info(after_action,"drt_parser_parse",t, scan);
#endif
            // We will not do a post skip!!!
            return hit;
        }

        template <typename RT, typename T, typename ScannerT, typename BaseT>
        inline RT
        drt_parser_parse(
            T const& t,
            ScannerT const& scan,
            drt_skipper_iteration_policy<BaseT> const&)
        {
#if defined(CNOME_DEBUG)
            debug_info(before_action,"drt_parser_parse",t, scan);
#endif

            t.deriv_action_before_parse(scan);

#if defined(CNOME_DEBUG)
            debug_info(before_parse,"drt_parser_parse",t, scan);
#endif
            RT hit = t.subject().parse(scan);

#if defined(CNOME_DEBUG)
            debug_info(after_parse,"drt_parser_parse",t, scan);
#endif

            t.deriv_action_after_parse(scan);

#if defined(CNOME_DEBUG)
            debug_info(after_action,"drt_parser_parse",t, scan);
#endif

            return hit;
        }

        template <typename RT, typename T, typename ScannerT>
        inline RT
        drt_parser_parse(
            T const& t,
            ScannerT const& scan,
			boost::spirit::classic::iteration_policy const&)
        {
#if defined(CNOME_DEBUG)
            debug_info(before_action,"drt_parser_parse",t, scan);
#endif

            t.deriv_action_before_parse(scan);

#if defined(CNOME_DEBUG)
            debug_info(before_parse,"drt_parser_parse",t, scan);
#endif

            RT hit = t.subject().parse(scan);


#if defined(CNOME_DEBUG)
            debug_info(after_parse,"drt_parser_parse",t, scan);
#endif

            t.deriv_action_after_parse(scan);

#if defined(CNOME_DEBUG)
            debug_info(after_action,"drt_parser_parse",t, scan);
#endif

            return hit;
        }

        template <
            typename RT,
            typename ParserT,
            typename ScannerT,
            typename BaseT>
        inline RT
        implicit_drt_parse(
            ParserT const& p,
            ScannerT const& scan,
            skipper_iteration_policy<BaseT> const&)
        {
            typedef scanner_policies<
                drt_iteration_policy<
                    BOOST_DEDUCED_TYPENAME ScannerT::iteration_policy_t>,
                BOOST_DEDUCED_TYPENAME ScannerT::match_policy_t,
                BOOST_DEDUCED_TYPENAME ScannerT::action_policy_t
            > policies_t;

#if defined(CNOME_DEBUG)
            debug_info(before_action,"implicit_drt_parse",p, scan);
#endif

            p.deriv_action_before_parse(scan);

#if defined(CNOME_DEBUG)
            debug_info(before_parse,"implicit_drt_parse",p, scan);
#endif

            scan.skip(scan);
            RT hit = p.subject().parse_main(scan.change_policies(policies_t(scan)));
            // We will not do a post skip!!!

#if defined(CNOME_DEBUG)
            debug_info(after_parse,"implicit_drt_parse",p, scan);
#endif

            p.deriv_action_after_parse(scan);

#if defined(CNOME_DEBUG)
            debug_info(after_action,"implicit_drt_parse",p, scan);
#endif

            return hit;
        }

        template <
            typename RT,
            typename ParserT,
            typename ScannerT,
            typename BaseT>
        inline RT
        implicit_drt_parse(
            ParserT const& p,
            ScannerT const& scan,
            drt_skipper_iteration_policy<BaseT> const&)
        {
#if defined(CNOME_DEBUG)
            debug_info(before_action,"implicit_drt_parse",p, scan);
#endif

            p.deriv_action_before_parse(scan);

#if defined(CNOME_DEBUG)
            debug_info(before_parse,"implicit_drt_parse",p, scan);
#endif

            RT hit = p.subject().parse_main(scan);

#if defined(CNOME_DEBUG)
            debug_info(after_parse,"implicit_drt_parse",p, scan);
#endif

            p.deriv_action_after_parse(scan);

#if defined(CNOME_DEBUG)
            debug_info(after_action,"implicit_drt_parse",p, scan);
#endif

            return hit;
        }

        template <typename RT, typename ParserT, typename ScannerT>
        inline RT
        implicit_drt_parse(
            ParserT const& p,
            ScannerT const& scan,
			boost::spirit::classic::iteration_policy const&)
        {
#if defined(CNOME_DEBUG)
            debug_info(before_action,"implicit_drt_parse",p, scan);
#endif

            p.deriv_action_before_parse(scan);

#if defined(CNOME_DEBUG)
            debug_info(before_parse,"implicit_drt_parse",p, scan);
#endif

            RT hit = p.subject().parse_main(scan);

#if defined(CNOME_DEBUG)
            debug_info(after_parse,"implicit_drt_parse",p, scan);
#endif

            p.deriv_action_after_parse(scan);

#if defined(CNOME_DEBUG)
            debug_info(after_action,"implicit_drt_parse",p, scan);
#endif

            return hit;
        }

    } // namespace impl

    ///////////////////////////////////////////////////////////////////////////
    //
    //  drt_iteration_policy class
    //
    ///////////////////////////////////////////////////////////////////////////
    template <typename BaseT>
    struct drt_iteration_policy : public BaseT
    {
        typedef BaseT base_t;

        drt_iteration_policy()
        : BaseT() {}

        template <typename PolicyT>
        drt_iteration_policy(PolicyT const& other)
        : BaseT(other) {}

        template <typename ScannerT>
        void
        skip(ScannerT const& /*scan*/) const {}
    };

#if defined(CNOME_DEBUG)

        enum Debug_Info_Status
        {
            before_action,
            before_parse,
            after_parse,
            after_action
        };

        template <typename CharT, typename T, typename ScannerT>
        inline void
        debug_info(
            Debug_Info_Status dbis,
            const CharT* msg,
            T const& t,
            ScannerT const& scan)
        {
            CharT* strAux;
            switch(dbis) {
                case before_action:
                    strAux = "before action";
                    break;
                case before_parse:
                    strAux = "before parser";
                    break;
                case after_parse:
                    strAux = "after parser";
                    break;
                case after_action:
                    strAux = "after action";
                    break;
            }

            std::string curScope;
			scopes::get_scope(curScope);

            std::cout << t.MyName() << ": " << msg << ":" << strAux << ": " << curScope << ", scope list size: " << var::scope.size() << std::endl;
        }

#endif

    template < template <typename ParserT> class DRT> 
    struct drt_parser_gen
    {

        template <typename ParserT>
        struct result {

            typedef DRT<ParserT> type;
        };

        template <typename ParserT>
        static DRT<ParserT>
        generate(boost::spirit::classic::parser<ParserT> const& subject)
        {
            return DRT<ParserT>(subject.derived());
        }

        template <typename ParserT>
        DRT<ParserT>
        operator[](boost::spirit::classic::parser<ParserT> const& subject) const
        {
            return DRT<ParserT>(subject.derived());
        }

    };

}} // namespace cnome { namespace directive {

#endif  // DIRECTIVE_BASE_H
